﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using Go.Tools;
using Go.Model;
using tpGo;
using System.Threading;
using Go;


namespace tpGo
{
    public partial class Tablero : Form, IObserver
    {
        public static int UPOFFSET = 50;
        public static int LEFTOFFSET = 50;
        private static int PIXELSIZEBOARD = 513;
        public static int DIMENSION = 9;
        public static int HEIGHT = (int)(PIXELSIZEBOARD / DIMENSION);

        public static int offset = HEIGHT;
        public int BOARDSIZE = ((HEIGHT * DIMENSION) - HEIGHT);
        private static String BOARDIMAGE;
        

        private static Dictionary<Coordinate, Intersection> board= new Dictionary<Coordinate, Intersection>();
        Thread modelGameThread;

        public static Tablero crearTablero9x9(Game aGame) {
            //DIMENSION = 9;
            BOARDIMAGE = ImageConstants.IMAGEBOARD9x9;
            return new Tablero(aGame);
        }

        public static Tablero crearTablero19x19(Game aGame)
        {
            //DIMENSION = 19;
            BOARDIMAGE = ImageConstants.IMAGEBOARD19x19;
            return new Tablero(aGame);
        }


        public Tablero(Game game)
        {
            InitializeComponent();
            startGame(game);
            setPlayersInfo(game.players().ToArray());
            game.Register(this);

        }

        public void setIntersectionObserver(Dictionary<Coordinate, Position> modelBoard)
        {
            foreach (KeyValuePair<Coordinate, Intersection> keyValue in board)
                modelBoard[keyValue.Key].Register(keyValue.Value);           
        }

        public void DrawPiedras(Graphics G)
        {
            foreach (KeyValuePair<Coordinate, Intersection> keyValue in board)
            {
                if (keyValue.Value.IsBussy)
                    keyValue.Value.draw();
            }       
        }

        public void DrawTablero(Graphics G)
        {
            Draw(ImageConstants.IMAGEBOARD9x9, PIXELSIZEBOARD, PIXELSIZEBOARD, new Point(LEFTOFFSET,UPOFFSET));            
        }


        public void Draw(string source, int weight, int height, Point pto)
        {
            Graphics graphics = this.CreateGraphics();
            System.Drawing.Pen pen = new System.Drawing.Pen(System.Drawing.Color.Green);
            Bitmap image = new Bitmap(source);
            image = new Bitmap(image, new Size(weight, height));
            graphics.DrawImage(image, pto);
        }


        private Coordinate transformPointToCoordinate(Point ptoMouse)
        {
            return Tools.getCoordinate(ptoMouse.X, ptoMouse.Y);
        }


        private Coordinate buscarCoordenadaEnTablero(Point ptoMouse)
        {
            if (!perteneceAlTablero(ptoMouse))
                throw new System.ArgumentException("Error cliqueo afuera del tablero");

            Coordinate _coordenada;
            Point puntoNormalizado = normalizarPunto(ptoMouse);
            _coordenada.x = (puntoNormalizado.X / HEIGHT);
            _coordenada.y = (puntoNormalizado.Y / HEIGHT);
            if ((puntoNormalizado.X % HEIGHT) > (HEIGHT / 2)) _coordenada.x += 1;
            if ((puntoNormalizado.Y % HEIGHT) > (HEIGHT / 2)) _coordenada.y += 1;
            if ((_coordenada.x >= 0) && (_coordenada.x <= DIMENSION) && (_coordenada.y >= 0) && (_coordenada.y <= DIMENSION))
            {
                return _coordenada;
            }

            throw new System.ArgumentException("Error cliqueo afuera del tablero");
        }

        private Boolean perteneceAlTablero(Point ptoMouse) 
        {
            return (ptoMouse.X >= LEFTOFFSET && ptoMouse.Y >= UPOFFSET) &&
                (ptoMouse.X <= LEFTOFFSET + PIXELSIZEBOARD && ptoMouse.Y <= UPOFFSET + PIXELSIZEBOARD);
        }

        private Point normalizarPunto(Point ptoMouse)
        {
            return new Point(ptoMouse.X-LEFTOFFSET,ptoMouse.Y-UPOFFSET);
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
 
            if (!ModelViewConnection.isActualPlayerHuman())
                return;
            Point puntoDelMouse = new Point(e.X, e.Y);
            if (estaEnTablero(puntoDelMouse))
            {
                Coordinate aCoordenada= buscarCoordenadaEnTablero(puntoDelMouse);
                if (ModelViewConnection.isValidMove(aCoordenada)){
                    ModelViewConnection.setMovimientoPendienteModelo(aCoordenada);
                    PlayerView.resetMensajeErrorJugada(ModelViewConnection.actualPlayer, this);
                } else { 
                    PlayerView.setMensajeErrorJugada(ModelViewConnection.actualPlayer, this);
                }
            }
        }

        private Boolean estaEnTablero(Point unPuntoDelMouse)
        {
            return UPOFFSET <= unPuntoDelMouse.Y && LEFTOFFSET <= unPuntoDelMouse.X &&
                        UPOFFSET + PIXELSIZEBOARD >= unPuntoDelMouse.Y && LEFTOFFSET + PIXELSIZEBOARD >= unPuntoDelMouse.X;     
        }

        private void setPlayersInfo(Player[] players)
        {
            setPlayer1Info(players[0]);
            setPlayer2Info(players[1]);
        }

        private void setPlayer1Info(Player aPlayer) {
            infoPlayer1Tipo.Text = "Tipo:" + aPlayer.playerType();
            infoPlayer1Color.Text = "Color:" + Functions.getColor(aPlayer.Color);
        }

        private void setPlayer2Info(Player aPlayer)
        {
            infoPlayer2Tipo.Text = "Tipo:" + aPlayer.playerType();
            infoPlayer2Color.Text = "Color:" + Functions.getColor(aPlayer.Color);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            this.Hide();
            this.Close();
            Form1 frm = new Form1();
            frm.ShowDialog();
            frm.Dispose();
        }

        private void startGame(Game game) {
            ModelViewConnection.setGame(game);
            ModelViewConnection.tablero=this;
            board = InterBoard.createTablero(DIMENSION, HEIGHT, this);

            modelGameThread = new Thread(ModelViewConnection.iniciar);
            modelGameThread.Start();
        }

        public void Dispose() {
            modelGameThread.Abort();
        }

        public void Tablero_Load(object sender, EventArgs e)
        {
           
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            if (ModelViewConnection.playerChange)
            {
                ModelViewConnection.resetPlayerChange();
                PlayerView.UpdatePlayer(ModelViewConnection.actualPlayer, this);
            }
            if (ModelViewConnection.isFinish) {
                ModelViewConnection.isFinish = false;
                finDelJuego(ModelViewConnection.winPlayer);
            }
        }
        
        private void finDelJuego(Player winPlayer){
            FinDelJuego fin = new FinDelJuego(winPlayer);
            fin.ShowDialog();
            fin.Dispose();
            this.Close();        
        }

        public void Update(Object sender)
        {
            Player winPlayer;
            if (sender == null)
                winPlayer = null;
            else
                winPlayer = (Player)sender;
            ModelViewConnection.gameFinish(winPlayer);
        }

    }
}
